# -*- coding: utf-8 -*-
"""
@Time    : 2024/8/6 20:05
@Author  : Gaoxuming
@FileName: segyv1.0.py
@Software: PyCharm
@Doc     : To process seismic(binary segy) data and conduct statistical analysis
"""
import os
import sys

import numpy as np
import segyio
import matplotlib.pyplot as plt
from prettytable import PrettyTable
import tkinter as tk
from tkinter import ttk, font
import pandas as pd
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

# ANSI escape codes for text formatting
RESET = "\033[0m"
BRIGHT = "\033[1m"
GREEN = "\033[32m"
RED = "\033[91m"
BLUE = "\033[94m"


def compare_segy_files(file1, file2, start_trace=0, error_threshold=1e-5, relative_error_threshold=0.001):
    """
    :param file1: arm segy文件所在路径，可以为绝对路径，也可以为脚本执行的相对路径
    :param file2: x86 segy文件所在路径，可以为绝对路径，也可以为脚本执行的相对路径
    :param start_trace: 开始比较的迹线编号，默认为0
    :param error_threshold: 绝对误差阈值
    :param relative_error_threshold: 相对误差阈值
    """
    # 比较文件大小
    size1 = os.path.getsize(file1)
    size2 = os.path.getsize(file2)

    print(f'{BRIGHT}文件 {BLUE}{file1}{RESET} 大小: {GREEN}{size1}{RESET} 字节')
    print(f'{BRIGHT}文件 {BLUE}{file2}{RESET} 大小: {GREEN}{size2}{RESET} 字节')
    # 检查文件大小是否一致
    if size1 == size2:
        print(f'{BRIGHT}{GREEN}文件大小一致{RESET}')
    else:
        print(f'{BRIGHT}{RED}文件大小不一致{RESET}')

    print('====' * 30)

    with segyio.open(file1, "r", endian='little', ignore_geometry=True) as segy1:
        # 读取所有迹线数据并转换为 NumPy 数组
        traces1 = np.array([trace for trace in segy1.trace[:]])

        # 获取EBCDIC文件头和二进制文件头
        # ebcidic_header1 = segy1.text[0]
        binary_header1 = segy1.bin

        # 打印二进制文件头
        print(f'{BRIGHT}文件 {BLUE}{file1}{RESET} 二进制文件头:{RESET}\n{binary_header1}')

        # 获取迹线总数
        total_traces1 = len(traces1)

        # 获取从start_trace开始的连续10个迹线的头部信息
        end_trace = min(start_trace + 10, total_traces1)
        headers1 = list(segy1.header[start_trace:end_trace])

    with segyio.open(file2, "r", endian='little', ignore_geometry=True) as segy2:
        # 读取所有迹线数据并转换为 NumPy 数组
        traces2 = np.array([trace for trace in segy2.trace[:]])

        # 获取EBCDIC文件头和二进制文件头
        # ebcidic_header2 = segy2.text[0]
        binary_header2 = segy2.bin

        # 打印二进制文件头
        print(f'{BRIGHT}文件 {BLUE}{file2}{RESET} 二进制文件头:{RESET}\n{binary_header2}')

        # 获取迹线总数
        total_traces2 = len(traces2)

        # 获取从start_trace开始的连续10个迹线的头部信息
        end_trace = min(start_trace + 10, total_traces2)
        headers2 = list(segy2.header[start_trace:end_trace])

    # 检查EBCDIC文件头是否一致
    # if ebcidic_header1 == ebcidic_header2:
    #     print(f'{BRIGHT}EBCDIC文件头一致{RESET}')
    # else:
    #     print(f'{BRIGHT}EBCDIC文件头不一致{RESET}')

    # 检查二进制文件头是否一致
    if binary_header1 == binary_header2:
        print(f'{BRIGHT}{GREEN}二进制文件头一致{RESET}')
    else:
        print(f'{BRIGHT}{RED}二进制文件头不一致{RESET}')

    print('====' * 30)
    # 打印从start_trace开始的连续10个道头信息
    print(
        f'{BRIGHT}文件 {BLUE}{file1}{RESET} 从迹线 {BLUE}{start_trace}{RESET} 到迹线 {BLUE}{end_trace - 1}{RESET} 的道头信息：{RESET}')
    for i, header in enumerate(headers1):
        print(f'Trace {start_trace + i}: {header}')

    # 打印从start_trace开始的连续10个道头信息
    print(
        f'{BRIGHT}文件 {BLUE}{file2}{RESET} 从迹线 {BLUE}{start_trace}{RESET} 到迹线 {BLUE}{end_trace - 1}{RESET} 的道头信息：{RESET}')
    for i, header in enumerate(headers2):
        print(f'Trace {start_trace + i}: {header}')

    # 比较从start_trace开始的连续10个迹线的头部信息
    print(f'迹线 {BLUE}{start_trace}{RESET} 到迹线 {BLUE}{end_trace - 1}{RESET} 的头部信息一致性比较：{RESET}')
    for i in range(end_trace - start_trace):
        if headers1[i] == headers2[i]:
            print(f'Trace Header Info {start_trace + i}: {GREEN}一致{RESET}')
        else:
            print(f'Trace Header Info {start_trace + i}: {RED}不一致{RESET}')

    print('====' * 30)
    # 计算绝对误差和相对误差
    absolute_diff = np.abs(np.abs(traces1) - np.abs(traces2))
    relative_diff = np.abs(absolute_diff / (np.abs(traces2) + 1e-10))  # 防止分母为零

    # 确定哪些点是噪点
    noise_mask = (absolute_diff > error_threshold) & (relative_diff > relative_error_threshold)
    noise_count = np.count_nonzero(noise_mask)

    # 最大值和最小值误差
    max_abs_error = np.abs(np.abs(np.max(traces1)) - np.abs(np.max(traces2)))
    min_abs_error = np.abs(np.abs(np.min(traces1)) - np.abs(np.min(traces2)))
    max_rel_error = max_abs_error / np.abs(np.max(traces2))
    min_rel_error = max_abs_error /(np.abs(np.min(traces2))+1e-10) #防止分母为零

    # 方差
    variance1 = np.var(traces1, ddof=0)
    variance2 = np.var(traces2, ddof=0)

    # 振幅比例
    abs_error_amplitude_range = np.abs(np.max(traces1 - traces2) - np.min(traces1 - traces2))
    A_sample_value = np.abs(np.max(traces1) - np.min(traces1))
    B_sample_value = np.abs(np.max(traces2) - np.min(traces2))
    sample_amplitude_range = A_sample_value if A_sample_value < B_sample_value else B_sample_value
    amplitude_ratio = abs_error_amplitude_range / sample_amplitude_range

    sample_num = len(traces1[0])
    total_trace = len(traces1)
    total_points = sample_num * total_trace
    print(f'{BRIGHT}单轨迹取样点数目(sample_num)：{GREEN}{sample_num}{RESET}')
    print(f'{BRIGHT}总轨迹数目(total_trace)：{GREEN}{total_trace}{RESET}')
    print(f'{BRIGHT}总点数(total_points)：{GREEN}{total_points}{RESET}')
    print(
        f'{BRIGHT}在绝对误差 {RED}{error_threshold}{RESET} 和相对误差 {RED}{relative_error_threshold * 100}% {RESET}范围下：')
    print(f'{BRIGHT}噪点数为：{GREEN}{noise_count}{RESET}')
    print(f'{BRIGHT}噪点数占总点数的百分比为：{GREEN}{noise_count / total_points:.2%}{RESET}')
    print(f'{BRIGHT}最大点绝对误差为：{GREEN}{max_abs_error}{RESET}')
    print(f'{BRIGHT}最小点绝对误差为：{GREEN}{min_abs_error}{RESET}')
    print(f'{BRIGHT}最大点相对误差为：{GREEN}{max_rel_error * 100:.10f}%{RESET}')
    print(f'{BRIGHT}最小点相对误差为：{GREEN}{min_rel_error * 100:.10f}%{RESET}')
    print(f'{BRIGHT}绝对误差的振幅为：{GREEN}{abs_error_amplitude_range}{RESET}')
    print(f'{BRIGHT}样本点的振幅为：{GREEN}{sample_amplitude_range}{RESET}')
    print(f'{BRIGHT}振幅比例为：{GREEN}{amplitude_ratio:.10%}{RESET}')
    print(f'{BRIGHT}{BLUE}{file1}{RESET}样本方差为：{GREEN}{variance1}{RESET}')
    print(f'{BRIGHT}{BLUE}{file2}{RESET}样本方差为：{GREEN}{variance2}{RESET}')

    # 创建表格
    table = PrettyTable()
    table.field_names = ["统计指标", "值"]
    # 设置列的最大宽度
    table._max_width[0] = 30  # 设置第一列的最大宽度
    table._max_width[1] = 20  # 设置第二列的最大宽度
    table.padding_width = 3  # 增加单元格内空白空间
    table.border = True  # 显示边框
    table.hrules = 1  # 显示所有水平边框
    table.vrules = 1  # 显示垂直边框
    table.align["统计指标"] = "l"  # 居中对齐统计指标列
    table.align["值"] = "l"  # 居中对齐值列

    # 添加数据行
    table.add_row(["单轨迹取样点数目", sample_num])
    table.add_row(["总轨迹数目", total_trace])
    table.add_row(["总点数", total_points])
    table.add_row(["噪点数", noise_count])
    table.add_row(["噪点数占总点数的百分比", f"{noise_count / total_points:.2%}"])
    table.add_row(["最大点绝对误差", max_abs_error])
    table.add_row(["最小点绝对误差", min_abs_error])
    table.add_row(["最大点相对误差", f"{max_rel_error * 100:.2f}%"])
    table.add_row(["最小点相对误差", f"{min_rel_error * 100:.2f}%"])
    table.add_row(["绝对误差的振幅", abs_error_amplitude_range])
    table.add_row(["样本点的振幅", sample_amplitude_range])
    table.add_row(["振幅比例", f"{amplitude_ratio:.2%}"])
    table.add_row([f"{file1} 样本方差", variance1])
    table.add_row([f"{file2} 样本方差", variance2])

    # 打印表格
    print(table)
    ###===============================以下代码为tk窗口，某些中文格式在centos不支持，暂不启用====================
    # data = {
    #     "统计指标": [
    #         "单轨迹取样点数目", "总轨迹数目", "总点数", "噪点数", "噪点数占总点数的百分比",
    #         "最大点绝对误差", "最小点绝对误差", "最大点相对误差", "最小点相对误差",
    #         "绝对误差的振幅", "样本点的振幅", "振幅比例",
    #         f"{file1} 样本方差", f"{file2} 样本方差"
    #     ],
    #     "值": [
    #         sample_num, total_trace, total_points, noise_count, f"{noise_count / total_points:.2%}",
    #         max_abs_error, min_abs_error, f"{max_rel_error * 100:.10f}%", f"{min_rel_error * 100:.10f}%",
    #         abs_error_amplitude_range, sample_amplitude_range, f"{amplitude_ratio:.10%}",
    #         variance1, variance2
    #     ]
    # }
    #
    # # 创建Pandas DataFrame
    # df = pd.DataFrame(data)
    #
    # # 创建Tkinter窗口
    # root = tk.Tk()
    # root.title(f"{file1} {file2}对比结果")
    # # 设置窗口的初始大小为800x600像素
    # root.geometry("1920x1080")
    # # 设置窗口的最大大小为1000x800像素
    # root.maxsize(2000, 1800)
    # # 设置字体为黑体，大小可以根据需要调整
    # font_prop = font.Font(family="SimHei", size=30)
    #
    # # 创建一个matplotlib图形
    # fig, ax = plt.subplots()
    #
    # # 设置matplotlib的字体
    # plt.rcParams['font.sans-serif'] = ['SimHei']
    # plt.rcParams['axes.unicode_minus'] = False
    #
    # # 使用Pandas绘图功能绘制表格
    # ax.axis('tight')
    # ax.axis('off')
    #
    # # 绘制表格，并设置字体大小和居中显示
    # the_table = ax.table(cellText=df.values, colLabels=df.columns, loc='center', cellLoc='center')
    # the_table.auto_set_font_size(False)
    # the_table.set_fontsize(20)  # 设置表格字体大小
    # the_table.scale(1, 2)  # 可以调整这个值来改变表格的大小
    #
    # # 调整子图参数，使得内容居中显示
    # plt.subplots_adjust(left=0.15, bottom=0.15, right=0.85, top=0.85, wspace=0.5, hspace=0.5)
    #
    # # 将matplotlib图形嵌入到Tkinter窗口
    # canvas = FigureCanvasTkAgg(fig, master=root)
    # canvas_widget = canvas.get_tk_widget()
    # canvas_widget.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
    #
    # # 应用字体到Tkinter标签
    # label = tk.Label(root, font=font_prop)
    # label.pack()
    #
    # # 启动Tkinter主循环
    # root.mainloop()


###===============================以上代码为tk窗口，某些中文格式在centos不支持，暂不启用====================

# return sample_num, total_trace, noise_count


# file1 = '11_bpfilter_AGC_SPARK_arm.segy'
# file2 = '11_bpfilter_AGC_SPARK_x86.segy'
# file1 = 'chai_10_harmdecon_arm.segy'
# file2 = 'chai_10_harmdecon_x86.segy'
# compare_segy_files(file1, file2)

if __name__ == '__main__':
    # 从命令行参数获取文件路径
    if len(sys.argv) < 3:
        print("请提供两个 SEG-Y 文件的路径作为参数，第一个参数为arm环境segy，第二个为x86环境segy文件")
        sys.exit(1)

    file1_path = sys.argv[1]
    file2_path = sys.argv[2]
    # 如果提供了第三个参数，则将其作为开始迹线的编号；否则，默认为0
    start_trace = int(sys.argv[3]) if len(sys.argv) > 3 else 0

    compare_segy_files(file1_path, file2_path, start_trace)
